export default class NewWebSocket {
  constructor (url = 'ws://localhost:9000', options = {}, handleMessage = (data) => { console.log(data) }) {
    this.options = options
    this.messageMap = {}
    this.subscribeMap = []
    this.waitSubMap = []
    this.repeatCount = 0 // 重新连接花费的次数，open事件触发后重置为0
    this.lockReconnect = false // 避免重复连接
    this.socket = null // websocket的实例
    this.url = url // websocket地址
    this.messageList = [] // 服务端推送数据做缓存，防止渲染频繁
    this.closeType = 'client' // 是否客服端主动断开链接 normol 服务端断开链接 client 客服端主动断开链接
    this.binaryType = options.binaryType || 'arraybuffer'
    this.renderTime = options.renderTime || 1 * 1000 // 数据需要快速渲染可适当调小
    this.timeout = options.timeout || 15 * 1000 // 心跳检测间隔15秒
    this.reconnectTime = options.reconnectTime || 5 * 1000 // 重连间隔
    this.reconnectTimeOut = options.reconnectTimeOut || 10 * 1000 // 心跳检测多久没响应则重连
    this.timeoutObj = null // 心跳检测定时器
    this.reconnectTimer = null // 重连定时器
    this.timeoutReconnectTimer = null // 断开重连定时器
    this.handleMessage = handleMessage
    this.init()
  }

  async init () {
    if (this.socket) {
      this.socket.onopen = this.socket.onclose = this.socket.onmessage = this.socket.onerror = null
    }
    console.log('----初始化socket----')
    // 初始化默认为需要服务端主动断开, 前端主动断开则为normal
    this.resetTimeOut()
    // 生成websocket对象
    const BrowserWebSocket = window.WebSocket || window.MozWebSocket
    // console.log('----new hoowebsocket---');
    const socket = new BrowserWebSocket(this.url)
    // socket属性
    socket.binaryType = this.binaryType
    socket.onopen = (event) => this.onOpen(event)
    socket.onclose = (event) => this.onClose(event)
    socket.onmessage = (event) => this.onMessage(event.data)
    socket.onerror = (err) => this.onError(err)
    this.socket = socket
  }

  onOpen (event) {
    console.log('----连接已建立----')
    console.log('openEvent:', event)
    // 订阅socket,开始心跳检测或者socket鉴权
    this.repeatCount = 0
    console.log('----建立连接第一次发送心跳检测----')
    this.socket.send('心跳测试')
    this.emit('open') // 触发open事件
    this.heartCheckStart()
  }

  onClose (event) {
    console.log('----连接已断开----')
    console.log('closeEvent:', event)
    console.log('type', this.closeType)
    if (this.closeType === 'normol') {
      // 关闭socket处理
    } else {
      // 其他原因或者服务器主动断开
      this.reconnect()
    }
  }

  onMessage (event) {
    console.log('----服务端响应数据----')
    console.log('messageEvent:', event)
    this.messageList.push(event)
    if (!this.messageTimer) {
      this.messageTimer = setTimeout(() => {
        this.messageList.forEach((item) => {
          this.handleMessage(item)
        })
        clearTimeout(this.messageTimer)
        this.messageList = []
        this.messageTimer = null
      }, this.renderTime)
    }
    this.heartCheckStart()
    try {
      const data = typeof event === 'string' ? event : JSON.parse(event)
      this.onReceiver({
        type: 'message',
        data: data
      })
    } catch (err) {
      console.log('messageErr:', err)
    }
  }

  onError (err) {
    console.log('onError', err)
    this.reconnect()
  }

  on (name, handler) {
    // 存储相应订阅后的回调
    this.messageMap[name] = handler
  }

  emit (name) {
    // 存储相应订阅后的回调
    const callback = this.messageMap[name]
    callback && callback()
  }

  onReceiver (data) {
    console.log(data) // 根据data返回的类型作出不同相应
    // const callback = this.messageMap[data.type];
    // if (callback) callback(data);
  }

  subscribe (data, callbackName, callback) {
    this.joinSubscribeMap(data)
    this.sendMessage(data)
    this.on(callbackName, callback)
  }

  unsubscribe (data) {
    this.deleteSubscribeMap(data)
    this.sendMessage(data)
  }

  joinSubscribeMap (data) {
    const subType = data.type
    let hasTopic = false
    this.subscribeMap.forEach((item) => {
      if (item.type === subType) {
        hasTopic = true
        return null
      }
    })
    if (!hasTopic) {
      this.subscribeMap.push(data)
    }
  }

  deleteSubscribeMap (data) {
    const subType = data.type
    this.subscribeMap.forEach((item, index) => {
      if (item.type === subType) {
        this.subscribeMap.splice(index, 1)
        return null
      }
    })
  }

  joinWaitSubscribeMap (data) {
    const subType = data.type
    let hasTopic = false
    this.waitSubMap.forEach((item) => {
      if (item.type === subType) {
        hasTopic = true
        return null
      }
    })
    if (!hasTopic) {
      this.waitSubMap.push(data)
    }
  }

  deleteWaitSubscribeMap (data) {
    const subType = data.type
    this.waitSubMap.forEach((item, index) => {
      if (item.type === subType) {
        this.waitSubMap.splice(index, 1)
        return null
      }
    })
  }

  sendMessage (data) {
    if (!this.socket) return
    const that = this
    const sendData = typeof data === 'string' ? data : JSON.stringify(data)
    console.log('readyState:', this.socket.readyState)
    if (this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(sendData)
      this.deleteWaitSubscribeMap(data)
    } else {
      this.joinWaitSubscribeMap(data)
      this.on('open', () => {
        that.waitSubMap.forEach((item) => {
          that.sendMessage(item)
        })
      })
    }
  }

  // 主动断开socket
  close () {
    if (!this.socket) return
    this.closeType = 'normol'
    this.socket.close()
    this.messageMap = {}
    this.waitSubMap = []
    this.socket = null
    this.timeoutObj && clearTimeout(this.timeoutObj)
    this.reconnectTimer && clearTimeout(this.reconnectTimer)
    this.timeoutReconnectTimer && clearTimeout(this.timeoutReconnectTimer)
    this.timeoutObj = null
    this.reconnectTimer = null
    this.timeoutReconnectTimer = null
  }

  reconnect () {
    console.log('----重新连接----')
    const self = this
    if (this.lockReconnect) return
    this.lockReconnect = true
    // 没连接上会一直重连，设置延迟避免请求过多
    this.reconnectTimer && clearTimeout(this.reconnectTimer)
    this.reconnectTimer = setTimeout(function () {
      self.init()
      self.lockReconnect = false
      self.repeatCount++
      console.log(`--重连次数：${self.repeatCount}--`)
      self.reconnect()
    }, this.reconnectTime)
  }

  // 开始心跳检测
  heartCheckStart () {
    const self = this
    clearTimeout(this.timeoutObj)
    clearTimeout(this.reconnectTimer)
    clearTimeout(this.timeoutReconnectTimer)
    this.timeoutObj = null
    this.reconnectTimer = null
    this.timeoutReconnectTimer = null
    // onmessage拿到返回的心跳就说明连接正常
    // 这里发送一个心跳，后端收到后，返回一个心跳消息，
    this.timeoutObj = setTimeout(() => {
      console.log('----发送心跳检测two----')
      self.socket.send('心跳测试')
      self.timeoutReconnectTimer = setTimeout(() => {
        self.reconnect()
      }, self.reconnectTimeOut)
    }, this.timeout)
  }

  resetTimeOut () {
    this.closeType = 'client'
    this.timeoutObj && clearTimeout(this.timeoutObj)
    this.reconnectTimer && clearTimeout(this.reconnectTimer)
    this.timeoutReconnectTimer && clearTimeout(this.timeoutReconnectTimer)
    this.timeoutObj = null
    this.reconnectTimer = null
    this.timeoutReconnectTimer = null
  }
}
